package com.easylinkin.linkappapi.powerdistribution.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.easylinkin.linkappapi.common.utils.ExpressionUtil;
import com.easylinkin.linkappapi.device.entity.Device;
import com.easylinkin.linkappapi.device.service.DeviceService;
import com.easylinkin.linkappapi.deviceattribute.constant.PhysicalModelTypeConstant;
import com.easylinkin.linkappapi.deviceattribute.entity.DeviceAttribute;
import com.easylinkin.linkappapi.deviceattributestatus.entity.DeviceAttributeStatus;
import com.easylinkin.linkappapi.deviceattributestatus.service.DeviceAttributeStatusService;
import com.easylinkin.linkappapi.powerdistribution.entity.DistributionCabinetConfiguration;
import com.easylinkin.linkappapi.powerdistribution.entity.DistributionCabinetConfigurationExpression;
import com.easylinkin.linkappapi.powerdistribution.entity.DistributionCabinetRefDevice;
import com.easylinkin.linkappapi.powerdistribution.entity.DistributionCabinetStatus;
import com.easylinkin.linkappapi.powerdistribution.mapper.DistributionCabinetStatusMapper;
import com.easylinkin.linkappapi.powerdistribution.service.DistributionCabinetAlarmInfoService;
import com.easylinkin.linkappapi.powerdistribution.service.DistributionCabinetConfigurationService;
import com.easylinkin.linkappapi.powerdistribution.service.DistributionCabinetRefDeviceService;
import com.easylinkin.linkappapi.powerdistribution.service.DistributionCabinetStatusService;
import org.apache.commons.lang3.ObjectUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 配电柜状态(冗余部分组态字段) 服务实现类
 * </p>
 *
 * @author TongJie
 * @since 2020-08-08
 */
@Service
public class DistributionCabinetStatusServiceImpl extends ServiceImpl<DistributionCabinetStatusMapper, DistributionCabinetStatus> implements DistributionCabinetStatusService {


    /**
     * 日志记录对象
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(DistributionCabinetStatusServiceImpl.class);

    @Resource
    private DeviceService deviceService;
    @Resource
    private DistributionCabinetConfigurationService distributionCabinetConfigurationService;
    @Resource
    private DistributionCabinetRefDeviceService distributionCabinetRefDeviceService;
    @Resource
    private DeviceAttributeStatusService deviceAttributeStatusService;
    @Resource
    DistributionCabinetAlarmInfoService distributionCabinetAlarmInfoService;

    @Override
    public void checkGenerateDistributionCabinetStatus(Device device) {
        Assert.notNull(device, "判断是否应产生组态状态，参数设备为空");
        Device originDevice = deviceService.findOneByDeviceCode(device.getCode());
        if (originDevice == null) {
            LOGGER.info("判断是否应产生组态状态，根据设备code查找不到设备，检查是否被删,code:" + device.getCode());
            return;
        }
        device.setDeviceUnitId(originDevice.getDeviceUnitId());

//        改逻辑 检测生成组态 改查实时状态表
        device.setDeviceAttributeStatusList(deviceAttributeStatusService.getLatestDeviceAttributeStatusList(device.getCode(),null));

        LOGGER.info("判断是否应产生组态状态，参数是:{}", JSONObject.toJSONString(device));
//      根据设备查找 配电柜关联设备以及组态以及组态的规则表达式
        List<DistributionCabinetRefDevice> cabinetRefDeviceList = distributionCabinetRefDeviceService.getCabinetRefDevicesWithConfigurationAndExpressions(device);

        if (CollectionUtils.isEmpty(cabinetRefDeviceList)) {
            LOGGER.info("查得所有配电柜关联设备为空");
            return;
        }
        for (DistributionCabinetRefDevice distributionCabinetRefDevice : cabinetRefDeviceList) {
            generateDistributionCabinetStatus(device, distributionCabinetRefDevice);
        }
        //配电柜指标告警
        distributionCabinetAlarmInfoService.triggerAlarm(device);
    }


    public void generateDistributionCabinetStatus(Device device, DistributionCabinetRefDevice distributionCabinetRefDevice) {
        LOGGER.info("generateDistributionCabinetStatus 检查产生组态状态方法被调用，distributionCabinetRefDevice 参数是：{}", JSONObject.toJSONString(distributionCabinetRefDevice));
        LOGGER.info("generateDistributionCabinetStatus 检查产生组态状态方法被调用，device 参数是：{}", JSONObject.toJSONString(device));

        List<DistributionCabinetConfiguration> distributionCabinetConfigurationList = distributionCabinetRefDevice.getDistributionCabinetConfigurationList();
        if (ObjectUtils.isEmpty(distributionCabinetConfigurationList)) {
            return;
        }
        for (DistributionCabinetConfiguration distributionCabinetConfiguration : distributionCabinetConfigurationList) {
            if (ObjectUtils.isEmpty(distributionCabinetConfiguration)) {
                LOGGER.info("配电柜对应的组态为空，组态状态规则是：{}", JSONObject.toJSONString(distributionCabinetRefDevice));
                continue;
            }
            if (checkIsMeetCondition(device, distributionCabinetConfiguration)) {
//                删除以前的该配电柜的状态信息
                QueryWrapper qw = new QueryWrapper();
                qw.eq("distribution_cabinet_id", distributionCabinetRefDevice.getDistributionCabinetId());
                remove(qw);

                DistributionCabinetStatus distributionCabinetStatus = new DistributionCabinetStatus();
                distributionCabinetStatus.setCreateTime(new Date());
                distributionCabinetStatus.setDistributionCabinetId(distributionCabinetRefDevice.getDistributionCabinetId());
                distributionCabinetStatus.setDistributionCabinetConfigurationId(distributionCabinetConfiguration.getId());
                save(distributionCabinetStatus);
                break;
            }
        }
    }

    private boolean checkIsMeetCondition(Device device, DistributionCabinetConfiguration distributionCabinetConfiguration) {

        List<DistributionCabinetConfigurationExpression> distributionCabinetConfigurationExpressionList = distributionCabinetConfiguration.getDistributionCabinetConfigurationExpressions();
        distributionCabinetConfigurationExpressionList.sort((a, b) -> {
            if (a.getSortNo() == null || b.getSortNo() == null) {
                return 0;
            }
            if (a.getSortNo() > b.getSortNo()) {
                return 1;
            } else if (a.getSortNo().equals(b.getSortNo())) {
                return 0;
            } else {
                return -1;
            }
        });
        if (CollectionUtils.isEmpty(distributionCabinetConfigurationExpressionList)) {
            LOGGER.info("无相应规则表达式");
            return true;
        }

        List<DeviceAttributeStatus> deviceAttributeStatusList = device.getDeviceAttributeStatusList();
        Assert.notEmpty(deviceAttributeStatusList, "设备属性状态为空");

//        检查设备状态不正常，默认false
        boolean isMeetCondition = false;

        for (DistributionCabinetConfigurationExpression configurationExpression : distributionCabinetConfigurationExpressionList) {
            Assert.notNull(configurationExpression.getDeviceAttribute(), "规则表达式对应属性id查到属性为空");
            isMeetCondition = getSingleCheckFromDeviceAttributeStatusListByAttrIdentifier(configurationExpression, deviceAttributeStatusList);
            if (isMeetCondition && "||".equals(configurationExpression.getLogicCode())) {
                return true;
            }
            if (!isMeetCondition && "&&".equals(configurationExpression.getLogicCode())) {
                return false;
            }
        }
        if (!isMeetCondition) {
            LOGGER.info("校验不满足智能规则表达式条件，方法将提前结束");
        }
        return isMeetCondition;
    }


    /**
     * 从设备属性状态中获取属性的值 判断单条属性判断结果值
     */
    private boolean getSingleCheckFromDeviceAttributeStatusListByAttrIdentifier(DistributionCabinetConfigurationExpression cabinetConfigurationExpression, List<DeviceAttributeStatus> deviceAttributeStatusList) {
        DeviceAttribute deviceAttribute = cabinetConfigurationExpression.getDeviceAttribute();
        boolean isMeetCondition = false;
        String deviceAttributeStatusValue;
        if (PhysicalModelTypeConstant.ARRAY_OBJECT.equals(deviceAttribute.getParentUnit())) {

            DeviceAttributeStatus deviceAttributeStatus = deviceAttributeStatusList.stream().filter(e -> deviceAttribute.getParentPropCode().equals(e.getPropCode())).findFirst().orElse(null);
            List<Map<String, Object>> children = JSONObject.parseObject(deviceAttributeStatus.getPropValue(), List.class);
            List<Object> values = children.stream().map(e -> e.get(deviceAttribute.getIdentifier())).collect(Collectors.toList());
            for (Object value : values) {
                isMeetCondition = ExpressionUtil.checkExpressionMeet(deviceAttribute.getUnit(), value.toString(), cabinetConfigurationExpression.getCalculateSign(), cabinetConfigurationExpression.getValue());

                if (isMeetCondition) {
                    return isMeetCondition;
                }
            }

        } else if (PhysicalModelTypeConstant.OBJECT.equals(deviceAttribute.getParentUnit())) {

            DeviceAttributeStatus deviceAttributeStatus = deviceAttributeStatusList.stream().filter(e -> deviceAttribute.getParentPropCode().equals(e.getPropCode())).findFirst().orElse(null);
            Map<String, Object> objectMap = JSONObject.parseObject(deviceAttributeStatus.getPropValue(), Map.class);

            isMeetCondition = ExpressionUtil.checkExpressionMeet(deviceAttribute.getUnit(), objectMap.get(deviceAttribute.getIdentifier()).toString(), cabinetConfigurationExpression.getCalculateSign(), cabinetConfigurationExpression.getValue());

        } else if (PhysicalModelTypeConstant.ARRAY_SIMPLE.equals(deviceAttribute.getUnit())) {

            DeviceAttributeStatus deviceAttributeStatus = deviceAttributeStatusList.stream().filter(e -> deviceAttribute.getIdentifier().equals(e.getPropCode())).findFirst().orElse(null);
            List<Object> values = JSONObject.parseObject(deviceAttributeStatus.getPropValue(), List.class);
            for (Object value : values) {

                isMeetCondition = ExpressionUtil.checkExpressionMeet(deviceAttribute.getUnit(), value.toString(), cabinetConfigurationExpression.getCalculateSign(), cabinetConfigurationExpression.getValue());

                if (isMeetCondition) {
                    return isMeetCondition;
                }
            }
        } else {
            DeviceAttributeStatus deviceAttributeStatus = deviceAttributeStatusList.stream().filter(e -> deviceAttribute.getIdentifier().equals(e.getPropCode())).findFirst().orElse(null);
            deviceAttributeStatusValue = deviceAttributeStatus != null ? deviceAttributeStatus.getPropValue() : null;
            if (ObjectUtils.isEmpty(deviceAttributeStatusValue)) {
                return false;
            }

            isMeetCondition = ExpressionUtil.checkExpressionMeet(deviceAttribute.getUnit(), deviceAttributeStatusValue, cabinetConfigurationExpression.getCalculateSign(), cabinetConfigurationExpression.getValue());

        }
        return isMeetCondition;
    }
}
